﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Mail;
using System.Text;
using System.Threading;
using nwrole.plugin;

namespace nwrole.lib {
    public class PluginWrapper : IPluginDebug {
        public IPlugin Plugin { get; private set; }
        //public IPluginDebug Debug { get; private set; }
        public Thread Thread { get; private set; }
        public TimeSpan StartDelay { get; set; }
        public PluginData PluginData { get; private set; }
        private PluginManager pluginManager;

        public PluginState PluginState { get; private set; }

        public PluginWrapper(IPlugin plugin, PluginData pluginData/*, IPluginDebug debug*/, PluginManager pluginManager) {
            StartDelay = new TimeSpan(0);
            Plugin = plugin;
            //Debug = debug;
            this.PluginData = pluginData;
            this.pluginManager = pluginManager;
            PluginState = PluginState.Stopped;
        }

        public void Start() {
            Thread = new Thread(ThreadStart);
            Thread.Start();
        }

        private void ThreadStart() {
            Log(LogLevel.Info, "PluginWrapper Starting plugin: " + PluginData.DisplayName, null);
            PluginState = PluginState.Starting;

            bool runAgain = true;

            while (runAgain)
            {
                runAgain = false;

                System.Threading.Thread.Sleep(StartDelay);
                try
                {
                    Log(LogLevel.Info, "PluginWrapper Running plugin: " + PluginData.DisplayName, null);
                    PluginState = PluginState.Running;
                    Plugin.Start(this);
                    Log(LogLevel.Info, "PluginWrapper Stopped (done) plugin: " + PluginData.DisplayName, null);
                    PluginState = PluginState.Stopped;
                }
                catch (Exception e)
                {
                    PluginState = PluginState.Faulted;
                    Log(LogLevel.Error, "PluginWrapper (Plugin:" + PluginData.DisplayName + ") : Unhandled plugin exception", e);


                    if (PluginData.RestartWhenFaulted)
                    {
                        runAgain = true;
                        pluginManager.SendFaultEmail(PluginData.DisplayName + " has faulted!", "The plugin " + PluginData.DisplayName + " has faulted and will shortly be restarted. Reason for fault: Unhandled plugin exception: " + e);
                    }
                    else
                    {
                        pluginManager.SendFaultEmail(PluginData.DisplayName + " has faulted!", "The plugin " + PluginData.DisplayName + " has faulted and is no longer running. Unhandled plugin exception: " + e);
                    }
                }
            }
            
        }

        public void Stop() {
            if (Thread == null || !Thread.IsAlive)
                return;

            Plugin.Stop();
            Thread.Join(TimeSpan.FromSeconds(10));
            Thread = null;
        }

        public void Log(LogLevel level, string message, Exception ex) {
            pluginManager.Log(NwroleObjectType.Plugin, PluginData.Id, level, message, ex);
        }

        public void Pulse(string message)
        {
            pluginManager.PulsePlugin(PluginData.Id, PluginData.DisplayName, message);
        }
    }
}
